home *** CD-ROM | disk | FTP | other *** search
- /*
- * A mount(8) for Linux 0.97.
- * $Header: /usr/src/mount/RCS/mount.c,v 1.1 1992/09/06 13:30:53 root Exp root $
- */
-
- #include "sundries.h"
-
- #include <linux/fs.h>
-
- const char *usage = "\
- Usage: mount [-anfrvw] [-t vfstypes]
- mount [-nfrvw] special | node
- mount [-nfrvw] [-t vfstype] [-o options] special node";
-
- #ifdef notyet
- /* True for change options of an already mounted fs (-u). */
- int update = 0;
- #endif
-
- /* True for fake mount (-f). */
- int fake = 0;
-
- /* Don't write a entry in /etc/mtab */
- int nomtab = 0;
-
- /* True for readonly (-r). */
- int readonly = 0;
-
- /* Nonzero for chatty (-v). */
- int verbose = 0;
-
- /* True for read/write (-w). */
- int readwrite = 0;
-
- /* True for all mount (-a). */
- int all = 0;
-
- /* Map from -o and fstab option strings to the flag argument to mount(2). */
- struct opt_map
- {
- const char *opt; /* option name */
- int inv; /* true if flag value should be inverted */
- int mask; /* flag mask value */
- };
-
- const struct opt_map opt_map[] =
- {
- { "defaults", 0, 0 }, /* default options */
- { "ro", 0, MS_RDONLY }, /* read-only */
- { "rw", 1, MS_RDONLY }, /* read-write */
- { "exec", 1, MS_NOEXEC }, /* permit execution of binaries */
- { "noexec", 0, MS_NOEXEC }, /* don't execute binaries */
- { "suid", 1, MS_NOSUID }, /* honor suid executables */
- { "nosuid", 0, MS_NOSUID }, /* don't honor suid executables */
- { "dev", 1, MS_NODEV }, /* interpret device files */
- { "nodev", 0, MS_NODEV }, /* don't interpret devices */
- { "sync", 0, MS_SYNC }, /* synchronous I/O */
- { "async", 1, MS_SYNC }, /* asynchronous I/O */
- #ifdef MS_NOSUB
- { "sub", 1, MS_NOSUB }, /* allow submounts */
- { "nosub", 0, MS_NOSUB }, /* don't allow submounts */
- #endif
- /* add new options here */
- #ifdef MS_REMOUNT
- { "remount", 0, MS_REMOUNT }, /* Alter flags of mounted FS */
- #endif
- { NULL, 0, 0 }
- };
-
-
- /* Report on a single mount. */
- static void
- print_one (const struct mntent *mnt)
- {
- printf ("%s on %s", mnt->mnt_fsname, mnt->mnt_dir);
- if ((mnt->mnt_type != NULL) && *mnt->mnt_type != '\0')
- printf (" type %s", mnt->mnt_type);
- if (mnt->mnt_opts != NULL)
- printf (" (%s)", mnt->mnt_opts);
- printf ("\n");
- }
-
- /* Report on everything in mtab (of the specified types if any). */
- static volatile int
- print_all (string_list types)
- {
- struct mntent *mnt;
-
- open_mtab ("r");
-
- while ((mnt = getmntent (F_mtab)) != NULL)
- if (matching_type (mnt->mnt_type, types))
- print_one (mnt);
-
- if (ferror (F_mtab))
- die (1, "mount: error reading %s: %s", MOUNTED, strerror (errno));
-
- exit (0);
- }
-
-
- /* Look for OPT in opt_map table and return mask value. If OPT isn't found,
- tack it onto extra_opts. Due to laziness, the first char of extra_opts
- will be ',' if any extra options are found. */
- static inline void
- parse_opt (const char *opt, int *mask, char *extra_opts)
- {
- const struct opt_map *om;
-
- for (om = opt_map; om->opt != NULL; ++om)
- if (streq (opt, om->opt))
- {
- if (om->inv)
- *mask &= ~om->mask;
- else
- *mask |= om->mask;
- return;
- }
- strcat (extra_opts, ",");
- strcat (extra_opts, opt);
- }
-
- /* Take -o options list and compute 4th and 5th args to mount(2). flags
- gets the standard options and extra_opts anything we don't recognize. */
- static void
- parse_opts (char *opts, int *flags, char **extra_opts, int *noauto)
- {
- char *opt;
-
- *noauto = 0;
- if (opts != NULL)
- {
- *extra_opts = xmalloc (strlen (opts) + 1);
- **extra_opts = '\0';
-
- for (opt = strtok (opts, ",");
- opt != NULL;
- opt = strtok (NULL, ","))
- if (streq (opt, "noauto"))
- *noauto = 1;
- else
- parse_opt (opt, flags, *extra_opts);
- }
-
- if (readonly)
- *flags |= MS_RDONLY;
- if (readwrite)
- *flags &= ~MS_RDONLY;
- }
-
- /* Fix opts_string to defaults if NULL, else merge readonly and readwrite.
- Simplistic, merging ``-r'' with ``-o rw''a will give ``ro,rw''. */
- static char *
- fix_opts_string (char *opts)
- {
- char *fixed;
-
- if (readonly || readwrite)
- {
- if (opts == NULL)
- return (readonly ? "ro" : "rw");
-
- fixed = xmalloc (strlen (opts) + 4);
-
- strcpy (fixed, readonly ? "ro," : "rw,");
- strcat (fixed, opts);
- return fixed;
- }
- return (opts == NULL ? "defaults" : opts);
- }
-
- /* Mount a single file system. Return status,
- so don't exit on non-fatal errors. */
- static int
- mount_one (char *spec, char *node, char *type, char *opts)
- {
- struct mntent mnt = {0};
- int mnt_err;
- int flags = 0;
- char *extra_opts = NULL;
- int noauto = 0;
-
- if (opts && streq (opts, "defaults"))
- opts = NULL;
-
- if (type == NULL)
- {
- if (strchr (spec, ':') != NULL)
- type = "nfs";
- else
- type = FSTYPE_DEFAULT;
- }
-
- parse_opts (xstrdup (opts), &flags, &extra_opts, &noauto);
-
- /* quietly succeed for fstab entries that don't get mounted automatically */
- if (all && noauto)
- return 0;
-
- if (!fake && streq (type, "nfs"))
- #ifdef HAVE_NFS
- if (nfsmount (spec, node, &flags, &opts, &extra_opts) != 0)
- return 1;
- #else
- die (1, "mount: this version of mount doesn't support the type nfs");
- #endif
-
- block_signals (SIG_BLOCK);
-
- if (fake || (mount5 (spec, node, type, flags, extra_opts)) == 0)
- /* Mount succeeded, write mtab entry. */
- {
- if (!nomtab) {
- mnt.mnt_fsname = canonicalize (spec);
- mnt.mnt_dir = canonicalize (node);
- mnt.mnt_type = type;
- mnt.mnt_opts = fix_opts_string (opts);
-
- /* We get chatty now rather than after the update to mtab since the
- mount succeeded, even if the write to /etc/mtab should fail. */
- if (verbose)
- print_one (&mnt);
-
- if (!fake && (addmntent (F_mtab, &mnt)) == 1)
- die (1, "mount: error writing %s: %s", MOUNTED, strerror (errno));
- }
-
- block_signals (SIG_UNBLOCK);
- return 0;
- }
- else
- mnt_err = errno; /* work around for errno bug in sigprocmask */
-
- block_signals (SIG_UNBLOCK);
-
- /* Mount failed, complain, but don't die. */
- switch (mnt_err)
- {
- case EPERM:
- if (geteuid() == 0)
- error ("mount: mount point %s is not a directory", node);
- else
- error ("mount: must be superuser to use mount");
- break;
- case EBUSY:
- error ("mount: wrong fs type, %s already mounted, %s busy, "
- "or other error", spec, node);
- break;
- case ENOENT:
- error ("mount: mount point %s does not exist", node); break;
- case ENOTDIR:
- error ("mount: mount point %s is not a directory", node); break;
- case EINVAL:
- error ("mount: %s not a mount point", spec); break;
- case EMFILE:
- error ("mount table full"); break;
- case EIO:
- error ("mount: %s: can't read superblock", spec); break;
- case ENODEV:
- error ("mount: fs type %s not supported by kernel", type); break;
- case ENOTBLK:
- error ("mount: %s is not a block device", spec); break;
- case ENXIO:
- error ("mount: %s is not a valid block device", spec); break;
- case EACCES:
- error ("mount: block device %s is not permitted on its filesystem", spec);
- break;
- default:
- error ("mount: %s", strerror (mnt_err)); break;
- }
- return 1;
- }
-
- /* Check if an fsname/dir pair was already in the old mtab. */
- static int
- mounted (char *spec, char *node, string_list spec_list, string_list node_list)
- {
- spec = canonicalize (spec);
- node = canonicalize (node);
-
- while (spec_list != NULL)
- {
- if (streq (spec, car (spec_list)) && streq (node, car (node_list)))
- return 1;
- spec_list = cdr (spec_list);
- node_list = cdr (node_list);
- }
- return 0;
- }
-
- /* Mount all filesystems of the specified types except swap and root. */
- static int
- mount_all (string_list types)
- {
- struct mntent *fstab;
- struct mntent *mnt;
- string_list spec_list = NULL;
- string_list node_list = NULL;
- int status;
-
- open_mtab ("r");
-
- while ((mnt = getmntent (F_mtab)))
- if (matching_type (mnt->mnt_type, types)
- && !streq (mnt->mnt_dir, "/")
- && !streq (mnt->mnt_dir, "root"))
- {
- spec_list = cons (xstrdup (mnt->mnt_fsname), spec_list);
- node_list = cons (xstrdup (mnt->mnt_dir), node_list);
- }
-
- close_mtab ();
-
- if (!nomtab) {
- lock_mtab ();
- open_mtab ("a+");
- unlink (MOUNTED_LOCK);
- }
-
- status = 0;
- while ((fstab = getfsent ()) != NULL)
- if (matching_type (fstab->mnt_type, types)
- && !streq (fstab->mnt_dir, "/")
- && !streq (fstab->mnt_dir, "root"))
- if (mounted (fstab->mnt_fsname, fstab->mnt_dir, spec_list, node_list))
- {
- if (verbose)
- printf("mount: %s already mounted on %s\n",
- fstab->mnt_fsname, fstab->mnt_dir);
- }
- else
- status |= mount_one (fstab->mnt_fsname,
- fstab->mnt_dir,
- fstab->mnt_type,
- fstab->mnt_opts);
-
- return status;
- }
-
- int
- main (int argc, char **argv)
- {
- int opt;
- char *options = NULL;
- string_list types = NULL;
- struct mntent *fs;
- char *spec;
-
- while ((opt = getopt (argc, argv, "naft:o:ruvw")) != EOF)
- switch (opt)
- {
- case 'a': /* mount everything in fstab */
- ++all;
- break;
- case 'f': /* fake (don't actually do mount(2) call) */
- ++fake;
- break;
- case 't': /* specify file system types */
- types = parse_types (optarg);
- break;
- case 'o': /* specify mount options */
- options = optarg;
- break;
- case 'r': /* mount readonly */
- ++readonly;
- break;
- case 'n': /* mount without writing in /etc/mtab */
- ++nomtab;
- break;
- #ifdef notyet
- /* Needs kernel support that we don't have yet, & some rewrites here also. */
- case 'u': /* change options on an already mounted fs */
- ++change;
- break;
- #endif
- case 'v': /* be chatty */
- ++verbose;
- break;
- case 'w': /* mount read/write */
- ++readwrite;
- break;
- default:
- die (2, usage);
- }
-
- argc -= optind;
- argv += optind;
-
- if (readonly && readwrite)
- die (2, "mount: the -r and -w options conflict\n%s", usage);
-
- if (argc == 0)
- if (options)
- die (2, usage);
- else if (all)
- return mount_all (types);
- else
- return print_all (types);
-
- if (!nomtab) {
- lock_mtab ();
- open_mtab ("a+");
- unlink (MOUNTED_LOCK);
- }
-
- switch (argc)
- {
- case 1:
- /* mount [-frvw] special | node */
- if ((types != NULL) || (options != NULL))
- die (2, usage);
- /* Try to find the other pathname in fstab. */
- spec = canonicalize (*argv);
- if (!(fs = getfsspec (spec)) && !(fs = getfsfile (spec)))
- die (2, "mount: can't find %s in %s\n", spec, _PATH_FSTAB);
- return mount_one (fs->mnt_fsname, fs->mnt_dir,
- fs->mnt_type, fs->mnt_opts);
- case 2:
- /* mount [-frvw] [-t vfstype] [-o options] special node */
- if (types == NULL)
- return mount_one (argv[0], argv[1], NULL, options);
- if (cdr (types) == NULL)
- return mount_one (argv[0], argv[1], car (types), options);
- die (2, usage);
-
- default:
- die (2, usage);
- }
- }
-